<?php

namespace app\api\extend;
use Firebase\JWT\JWT;
use think\exception\ValidateException;
use think\facade\Config;
use think\facade\Request;
use think\response\Json;

/**
 * 控制器公共类
 */
class Common{
	// 请求变量
	protected $request;
	// 请求参数
	protected $params;
    //token秘钥
    protected $key = 'vVR1LmHiQm1Dy94VkkyT7xRF5A0z3h';
    // 加密前缀
    private $pre = '_api';
    // 加密后缀
    private $suf = 'api_';
	// 常量数组
	protected $constant;
	// 控制器模型
    protected $model;
    // 验证器名称
    protected $valida;
    //模型前缀
    private $model_class_prefix = 'app\api\model\\';
    //验证器前缀
    private $validate_class_prefix = 'app\api\validate\\';

    /**
     * 初始化属性
     */
    public function __construct() {
        // 初始化配置项
        $this->initConfig();
        // 初始化页面传参数
        $this->initParams();
        // 初始化模型
        $this->initModel();
        //初始化验证器
        $this->initValidate();
    }
    /**
     * 初始化配置项
     * @return void
     */
    private function initConfig(){
        // 初始化常量
        $this->constant = Config::get('index.constants');
    }
    /**
     * 初始化页面传参数
     * @return void
     */
    private function initParams()
    {
        // 获取请求体
        $this->request = Request::instance();
        // 获取页面传参
        $this->params = $this->request->param();
        // 判断是否存在用户id
        // if (isset($this->request->auth)) {
        //     // 将用户id存储到页面
        //     $this->params[''] = $this->getAuthArg();
        // }
        // 获取页面参数，并且修改所有起始字符串是[ 结束字符串是 ] 的字符串，将其传转化为数组
        // foreach ($this->params as $key => $value) {
        //     if (str_starts_with($value, '[') && str_ends_with($value, ']')) {
        //         $this->params[$key] = json_decode($value);
        //         break;
        //     }
        // }
    }
    /**
     * 初始化模型
     * @return void
     */
    private function initModel()
    {
        $model_name = $this->model_class_prefix . $this->request->controller();
        // 判断是否有这个类
        if (class_exists($model_name)) {
            // 初始化模型类
            $this->model = new $model_name;
        }
    }
    /**
     * 初始化验证器
     * @return void
     */
    private function initValidate()
    {
        $valida = $this->validate_class_prefix . $this->request->controller();
        // 判断是否有这个类
        if (class_exists($valida)) {
            // 初始化模型类
            $this->valida = $valida;
        }
    }

    /**
     * 加密函数
     * @param  string $data 加密内容
     * @return string 返回加密数据
     */
    public function encipher(string $data): string
    {
        return md5(md5($this->pre) . md5($data) .md5($this->suf));
    }

    /**
     * 验证页面参数
     * @param boolean $isScenario  是否存在验证场景
     * @return array|Json 成功返回array，验证失败返回Json
     */
    public function check_params(bool $isScenario=false,bool $batch = false) {
        try {
            if ($batch && $isScenario) {
                validate($this->valida)->batch(true)->scene($this->request->action())->check($this->params);
            }elseif($isScenario){
                validate($this->valida)->scene($this->request->action())->check($this->params);
            }else{
                 validate($this->valida)->check($this->params);
            }
            /* **********如果不用加前缀可以注释掉(start)********** */
            // $arr=[];
            // foreach ($this->params as $key => $value) {
            //     $arr[$this->request->controller(true).'_'.$key] = $value;
            // }
            // return $arr;
            /* **********end********** */
        } catch (ValidateException $e) {
            // 验证失败 返回错误信息
            return $e->getMessage();
        }
    }

    /**
     * 返回json信息
     * @param  int  $code 状态码
     * @param  string  $msg  描述信息
     * @param array $data 参数
     * @param boolean $flag 是否添加data数组，否则遍历data数组将下标和值添加到res数组
     * @return Json 返回一个json格式对象
     */
    public function return_msg($code, $msg,  $data = [],$flag = true): Json
    {
        $res = [
            'code' => $code,
            'msg' => $msg,
        ];
        if (!empty($data)) {
             $res['data'] = $data;
        } else if (!$flag) {
            foreach ($data as $key => $val) {
                $res[$key] = $val;
            }
        }
        return json($res);
    }


	/**
	 * 获取常量值
	 * @param boolean $isSuccess 判断是否为获取成功信息
	 * @return string 如果$isSuccess为true返回success的内容，否则返回失败信息
	 */
	public function getConst(bool $isSuccess = true): string
    {
		return $this->constant[$this->request->controller()][$this->request->action()][$isSuccess];
	}

	/**
	 * 获取token中的参数
	 * @param string $name 参数名称
	 * @return string|null  如果有这个参数返回string,否则返回NULL
	 */
	public function getAuthArg(string $name = 'userId'): ?string
    {
		if (isset($this->request->auth)) {
			return $this->request->auth[$name];
		}
        return null;
	}

    /**
     * 生成token
     * @param string $data 携带参数
     * @param string $key    令牌
     * @return string        token字符串
     */
    function generateToken(array $data, string $key): string
    {
        $payload = array(
            "iss" => "http://www.test2.com", // 签发者
            "aud" => "http://www.test2.com", // 接收方
            "iat" => time(), // 签发时间
            "nbf" => time(), // 生效时间
            "data" => $data,
            "exp" => time() + (60 * 60 *24), // 过期时间 设置1小时
        );

        return JWT::encode($payload, $key, 'HS256');
    }

	/**
	 * 上传文件
	 * @param string $savePath  保存路径
	 * @param string $fieldName 文件名
	 * @param string $desc      错误信息描述
	 */
	public function uploadFile( $file,  $desc = '文件', $savePath = 'uploads') {	
		// 验证文件是否上传成功
		if (empty($file)) {
			return false;
		}
        // 判断是否有多个文件
        if (is_array($file) && count($file) > 1) {
            $fileNames = [];
            // 有多个文件上传
            foreach($file as $item) {
                // 移动文件到指定目录
                $newSavePath = $this->createDateBasedFolder($savePath);
                $saveName = md5(uniqid()) . '.' . $item->getOriginalExtension();
                if ($item->move($newSavePath, $saveName)) {
                    $fileName = $newSavePath . $saveName;
                    $fileNames[] = Config::get('index.baseImageUrl').$fileName;
                }else {
                    // 文件保存失败
                    return false;
                }
            }
            return $fileNames;
        }
        // 移动文件到指定目录
        $savePath = $this->createDateBasedFolder($savePath);
        $saveName = md5(uniqid()) . '.' . $file->getOriginalExtension();
        // 保存文件
        if ($file->move($savePath, $saveName)) {
            return Config::get('index.baseImageUrl') . '/' . $savePath . $saveName;
        } else {
            // 文件保存失败
            return false;
        }
	}

	/**
	 * 创建上传文件目录
	 * @param string $basePath 根目录
	 * @return string  文件夹路径
	 */
	public function createDateBasedFolder(string $basePath = 'uploads/'): string
    {
		// 获取当前日期
		$date = date('Y-m-d'); // 格式为 年月日，例如 2025-04-01
		// 构造完整的文件夹路径
		$folderPath = $basePath . '/' . $date . '/';
		// 检查文件夹是否存在，如果不存在则创建
		if (!file_exists($folderPath)) {
			mkdir($folderPath, 0777, true); // 第二个参数是权限，第三个参数表示递归创建
		}
		// 返回创建的文件夹路径
		return $folderPath;
	}

    public function mergeSort($array) {  
    // 基本情况：如果数组只有一个元素或为空，则直接返回  
    if (count($array) <= 1) {  
        return $array;  
    }  
  
    // 找到数组的中间点，将数组分成两部分  
    $middle = intdiv(count($array), 2);  
    $left = array_slice($array, 0, $middle);  
    $right = array_slice($array, $middle);  
  
    // 递归地对两部分进行排序  
    $left = mergeSort($left);  
    $right = mergeSort($right);  
  
    // 合并两个已排序的部分  
    return merge($left, $right);  
}  
  
public function merge($left, $right) {  
    $result = [];  
    $leftIndex = 0;  
    $rightIndex = 0;  
  
    // 合并两个数组，直到其中一个被完全合并  
    while ($leftIndex < count($left) && $rightIndex < count($right)) {  
        if ($left[$leftIndex]['timestamp'] >= $right[$rightIndex]['timestamp']) {  
            $result[] = $left[$leftIndex];  
            $leftIndex++;  
        } else {  
            $result[] = $right[$rightIndex];  
            $rightIndex++;  
        }  
    }  
  
    // 如果左数组还有剩余元素，则将它们添加到结果中  
    while ($leftIndex < count($left)) {  
        $result[] = $left[$leftIndex];  
        $leftIndex++;  
    }  
  
    // 如果右数组还有剩余元素，则将它们添加到结果中  
    while ($rightIndex < count($right)) {  
        $result[] = $right[$rightIndex];  
        $rightIndex++;  
    }  
  
    return $result;  
}  

function generateRandomUsername($length = 8) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomUsername = '';
    for ($i = 0; $i < $length; $i++) {
        $randomUsername .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomUsername;
}
  
}